#include "QFillOperationWidget.h"

#include "Core/MainWindow.h"
#include <TopExp.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <ShapeFix_Wire.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepClass3d_SolidClassifier.hxx>
#include <ShapeFix_Face.hxx>
#include "FeatureShape/ShapeOperation.h"
#include "FeatureShape/HistoryManager.h"
#include <GProp_GProps.hxx>
#include "BRepGProp.hxx"


struct PntComparator
{
	bool operator()(const gp_Pnt& p1, const gp_Pnt& p2) const
	{
		if (p1.Distance(p2) < 0.01)
		{
			return false;
		}
		//if (!IsNearlyEqual(p1.X(), p2.X()), 0.01) return p1.X() < p2.X();
		//if (!IsNearlyEqual(p1.Y(), p2.Y()), 0.01) return p1.Y() < p2.Y();
		//if (!IsNearlyEqual(p1.Z(), p2.Z()), 0.01) return p1.Z() < p2.Z();
		return false;
	}
};

QFillOperationWidget::QFillOperationWidget(MainWindow* inMainWindow, ShapeOperation* inOperation, QWidget* parent)
	: QRSWidgetBase(inMainWindow, inOperation, parent)
	, ui(new Ui::QFillOperationWidgetClass())
{
	ui->setupUi(this);

	ui->selectEdgesTable->setColumnCount(2);
	// 设置水平表头标签
	QStringList headers;
	headers << "曲线" << "解释";
	ui->selectEdgesTable->setHorizontalHeaderLabels(headers);

	// 设置表头样式
	ui->selectEdgesTable->horizontalHeader()->setStyleSheet(
		"QHeaderView::section{"
		"background-color: lightblue;"
		"color: black;"
		"border: 1px solid #6c6c6c;"
		"}"
	);

	// 设置 QTableWidget 的样式表以更改所有单元格的文本颜色
	ui->selectEdgesTable->setStyleSheet(
		"QTableWidget::item {"
		"color: black;"
		"}"
	);

	connect(ui->modifyButton, &QPushButton::clicked, this, &QFillOperationWidget::OnModify);
	connect(ui->confirmButton, &QPushButton::clicked, this, &QFillOperationWidget::OnConfirm);
	connect(ui->cancelButton, &QPushButton::clicked, this, &QFillOperationWidget::close);

	connect(m_mainWindow, &MainWindow::OnSelectedSubShapes, this, &QFillOperationWidget::OnSelectedSubShapes);
}

QFillOperationWidget::~QFillOperationWidget()
{
	delete ui;
}

void QFillOperationWidget::OnSelectedSubShapes(QIVtkSelectionPipeline* actor)
{
	if (!m_mainWindow->GetSelectedShapes().size())
	{
		return;
	}

	const TopoDS_Shape& selectedShape = m_mainWindow->GetSelectedShapes().back();
	if (selectedShape.ShapeType() == TopAbs_EDGE)
	{
		TopoDS_Edge edge = TopoDS::Edge(selectedShape);
		selectEdges.push_back(edge);
	}

	auto rowCount = ui->selectEdgesTable->rowCount();
	ui->selectEdgesTable->insertRow(rowCount);
	ui->selectEdgesTable->setItem(rowCount, 0, new QTableWidgetItem(QString("边") + QString::number(rowCount + 1)));
	ui->selectEdgesTable->setItem(rowCount, 1, new QTableWidgetItem(QString("无")));

	selectActors.insert(actor);
}

void QFillOperationWidget::closeEvent(QCloseEvent* event)
{
	disconnect(m_mainWindow, &MainWindow::OnSelectedSubShapes, this, &QFillOperationWidget::OnSelectedSubShapes);

	m_mainWindow->SubWidgetClose(bIsConfirmed);
}

void QFillOperationWidget::OnModify()
{
	FillFace();

	selectEdges.clear();
	selectActors.clear();
}

void QFillOperationWidget::OnConfirm()
{
	bIsConfirmed = true;

	FillFace();

	close();
}

void QFillOperationWidget::FillFace()
{
	// 1.将edge转化为wire
    std::cout << "QFillOperationWidget::Edge Num:" << selectEdges.size() << std::endl;
	std::vector<TopoDS_Wire> wires = BuildWiresFromEdges(selectEdges);
	std::cout << "QFillOperationWidget::HandleWire Num:" << wires.size() << std::endl;
	// 2.将wire转化为face
	TopoDS_Face face = CreateFaceWithHoles(wires);
	// 3.根据face生成actor
	Handle(QIVtkSelectionPipeline) faceActor = m_mainWindow->createBasicUnitActor(face, true);

	std::vector<std::pair<int, std::vector<int>>> operationParams;
	for (auto* actor : selectActors)
	{
		std::pair<int, std::vector<int>> pair;
		pair.first = GetIndexFromActor(m_mainWindow->GetCachedActors(), actor);

		int i = 0;
		TopExp_Explorer explorer(actor->OccShape(), TopAbs_EDGE);
		while (explorer.More())
		{
			bool bFind = std::find_if(selectEdges.begin(), selectEdges.end(),
				[&explorer](std::reference_wrapper<const TopoDS_Shape> shape)
				{
					return shape.get().IsEqual(explorer.Current());
				}) != selectEdges.end();
			if (bFind)
			{
				pair.second.push_back(i);
			}
			explorer.Next();
			i++;
		}
        operationParams.push_back(pair);
	}

	FillFaceOperation* op = new FillFaceOperation("填充曲线", operationParams);
	m_mainWindow->GetHistoryManager()->applyOperation(op);

	if (ui->deleteSource->isChecked())
	{
		for (auto* actor : selectActors)
		{
			m_mainWindow->RemoveActorFromRenderer(actor);
		}
	}
}

std::tuple<std::vector<TopoDS_Wire>, std::vector<TopoDS_Edge>> QFillOperationWidget::PreprocessEdges(const std::vector<TopoDS_Edge>& edges)
{
	std::vector<TopoDS_Wire> closedWires;
	std::vector<TopoDS_Edge> nonClosedEdges;

	for (const auto& edge : edges)
	{
		// 检查边是否有效
		TopoDS_Vertex V1, V2;
		TopExp::Vertices(edge, V1, V2);
		if (V1.IsNull() || V2.IsNull())
		{
			continue; // 剔除无效边
		}

		// 判断边是否闭合
		if (V1.IsSame(V2) || BRep_Tool::IsClosed(edge))
		{
			// 直接生成闭合线框
			BRepBuilderAPI_MakeWire wireMaker;
			wireMaker.Add(edge);
			if (wireMaker.IsDone())
			{
				closedWires.push_back(wireMaker.Wire());
			}
		}
		else
		{
			nonClosedEdges.push_back(edge);
		}
	}

	return { closedWires, nonClosedEdges };
}

std::vector<TopoDS_Wire> QFillOperationWidget::BuildWiresFromEdges(const std::vector<TopoDS_Edge>& edges)
{
	std::vector<TopoDS_Wire> resultWires;
	// 步骤1：预处理，分离闭合边和非闭合边
	auto [closedWires, nonClosedEdges] = PreprocessEdges(edges);
	resultWires.insert(resultWires.end(), closedWires.begin(), closedWires.end());
	if (nonClosedEdges.empty()) return resultWires;

	// 步骤2：构建顶点-边映射（基于几何坐标）
	std::map<gp_Pnt, TopTools_ListOfShape, PntComparator> vertexEdgeMap;
	for (const auto& edge : nonClosedEdges)
	{
		TopoDS_Vertex V1, V2;
		TopExp::Vertices(edge, V1, V2);
		gp_Pnt P1 = BRep_Tool::Pnt(V1);
		gp_Pnt P2 = BRep_Tool::Pnt(V2);

		vertexEdgeMap[P1].Append(edge);
		vertexEdgeMap[P2].Append(edge);
	}

	// 步骤3：遍历生成闭合线框
	TopTools_MapOfShape visitedEdges;
	const double tolerance = 0.01; // 自定义容差

	while (visitedEdges.Extent() < nonClosedEdges.size())
	{
		// 找到第一条未访问的边
		TopoDS_Edge startEdge;
		for (const auto& edge : nonClosedEdges)
		{
			if (!visitedEdges.Contains(edge))
			{
				startEdge = edge;
				break;
			}
		}

		BRepBuilderAPI_MakeWire wireMaker;
		wireMaker.Add(startEdge);
		visitedEdges.Add(startEdge);

		// 记录起点和终点
		TopoDS_Vertex startV, endV;
		TopExp::Vertices(startEdge, startV, endV);
		gp_Pnt startPnt = BRep_Tool::Pnt(startV);
		gp_Pnt currentPnt = BRep_Tool::Pnt(endV);

		bool isClosed = false;
		while (!isClosed)
		{
			bool foundNextEdge = false;
			auto it = vertexEdgeMap.find(currentPnt);
			if (it == vertexEdgeMap.end()) break;

			// 找到一条未被访问的关联边
			for (TopTools_ListIteratorOfListOfShape lit(it->second); lit.More(); lit.Next())
			{
				TopoDS_Edge nextEdge = TopoDS::Edge(lit.Value());
				// 已被访问则跳过
				if (visitedEdges.Contains(nextEdge)) continue;

				// 获得关联边的端点坐标
				TopoDS_Vertex nextV1, nextV2;
				TopExp::Vertices(nextEdge, nextV1, nextV2);
				gp_Pnt nextP1 = BRep_Tool::Pnt(nextV1);
				gp_Pnt nextP2 = BRep_Tool::Pnt(nextV2);

				currentPnt = nextP2; // 移动到终点

				// 如果终点是关联边的终点，则反转关联边
				if (nextP2.IsEqual(currentPnt, tolerance))
				{
					// 反转之后获取的坐标值没有发生变换
					nextEdge.Reverse();
					currentPnt = nextP1;
					//TopExp::Vertices(nextEdge, nextV1, nextV2); // 更新顶点
					//nextP1 = BRep_Tool::Pnt(nextV1); // 重新提取坐标
					//nextP2 = BRep_Tool::Pnt(nextV2);
				}

				wireMaker.Add(nextEdge);
				visitedEdges.Add(nextEdge);
				foundNextEdge = true;

				// 检查几何闭合性
				if (currentPnt.IsEqual(startPnt, tolerance))
				{
					isClosed = true;
				}
				break;
			}
			// 若不存在关联边，直接退出循环
			if (!foundNextEdge) break;
		}

		// 直接添加修复后的线框
		if (wireMaker.IsDone())
		{
			TopoDS_Wire wire = wireMaker.Wire();
			ShapeFix_Wire fixWire;
			fixWire.Load(wire);
			fixWire.Perform();
			// 闭合wire才添加
			if (BRep_Tool::IsClosed(wire))
			{
				resultWires.push_back(fixWire.Wire());
			}
		}
	}

	return resultWires;
}

TopoDS_Face QFillOperationWidget::CreateFaceWithHoles(std::vector<TopoDS_Wire>& wires)
{
	// 步骤1：修复所有线框方向（初始假设为内圈顺时针）
	for (auto& wire : wires) 
	{
		FixWireOrientation(wire, /*isOuter=*/false);
	}

	// 步骤2：确定外圈
	TopoDS_Wire outerWire = FindOuterWire(wires);
	//std::cout << "outerWire:" << IsWireClockwise(outerWire) << std::endl;
	outerWire.Reverse();
	//std::cout << "outerWire:" << IsWireClockwise(outerWire) << std::endl;
	std::vector<TopoDS_Wire> innerWires;

	// 步骤3：收集内圈（被外圈包含的线框）
	for (auto& wire : wires)
	{
		if (!wire.IsSame(outerWire))
		{
			//std::cout << "innerWires:" << IsWireClockwise(wire) << std::endl;
			//wire.Reverse();
			//std::cout << "innerWires:" << IsWireClockwise(wire) << std::endl;
			innerWires.push_back(wire);
			
		}
	}

	// 步骤4：生成面
	BRepBuilderAPI_MakeFace faceMaker(outerWire, true);
	for (const auto& inner : innerWires)
	{
		faceMaker.Add(inner);
	}

	if (!faceMaker.IsDone())
	{
		qDebug() << "生成面失败！";
		return TopoDS_Face();
	}

	ShapeFix_Face fixer(faceMaker.Face());
	fixer.Perform();

	return fixer.Face();
}

TopoDS_Wire QFillOperationWidget::FindOuterWire(std::vector<TopoDS_Wire>& wires)
{
	// #TODO:未考虑多层wire嵌套关系（存在多个外圈wire，会形成多个face）
	// #TODO:未考虑wire交叉情况
	// wire所形成的面积最大即为外圈wire
	double maxArea = -1;
	TopoDS_Wire outerWire;
	for (auto& wire : wires)
	{
		double area = GetWireArea(wire);
		if (area > maxArea)
		{
            outerWire = wire;
			maxArea = area;
		}
	}

	if (maxArea < 0)
	{
		qDebug() << "未找到外圈线框！";
	}
	return outerWire;
	

	// 已被废弃
	//for (auto& candidate : wires)
	//{
	//	bool isOuter = true;
	//	for (auto& other : wires)
	//	{
	//		if (candidate.IsSame(other)) continue;
	//		if (IsWireInside(other, candidate))
	//		{ // 如果 candidate 被 other 包含
	//			isOuter = false;
	//			break;
	//		}
	//	}
	//	if (isOuter)
	//	{
	//		return candidate; // 找到最外层线框
	//	}
	//}
	//qDebug() << "未找到外圈线框！";
	//return TopoDS_Wire();
}

bool QFillOperationWidget::IsWireInside(const TopoDS_Wire& outer, const TopoDS_Wire& inner)
{
	// 生成外圈的面
	BRepBuilderAPI_MakeFace outerFaceMaker(outer);
	if (!outerFaceMaker.IsDone()) return false;
	TopoDS_Face outerFace = outerFaceMaker.Face();

	// 取内圈的一个顶点作为测试点
	TopoDS_Vertex aVertex;
	TopExp_Explorer exp(inner, TopAbs_VERTEX);
	if (!exp.More()) return false;
	aVertex = TopoDS::Vertex(exp.Current());
	gp_Pnt testPoint = BRep_Tool::Pnt(aVertex);

	// 分类器判断点是否在面内部
	BRepClass3d_SolidClassifier classifier(outerFace, testPoint, Precision::Confusion());
	return classifier.State() == TopAbs_IN;
}

bool QFillOperationWidget::IsWireClockwise(const TopoDS_Wire& wire)
{
	std::vector<gp_Pnt> vertices;

	// 提取顶点
	TopExp_Explorer edgeExplorer(wire, TopAbs_EDGE);
	TopoDS_Edge currentEdge = TopoDS::Edge(edgeExplorer.Current());
	TopoDS_Vertex firstStart, firstEnd;
	TopExp::Vertices(currentEdge, firstStart, firstEnd);
	vertices.push_back(BRep_Tool::Pnt(firstStart));
	vertices.push_back(BRep_Tool::Pnt(firstEnd));

	for (edgeExplorer.Next(); edgeExplorer.More(); edgeExplorer.Next())
	{
		currentEdge = TopoDS::Edge(edgeExplorer.Current());
		TopoDS_Vertex v1, v2;
		TopExp::Vertices(currentEdge, v1, v2);
		vertices.push_back(BRep_Tool::Pnt(v2));
	}

	// 计算有符号面积
	double signedArea = 0.0;
	int n = vertices.size();
	for (int i = 0; i < n; ++i)
	{
		const gp_Pnt& p1 = vertices[i];
		const gp_Pnt& p2 = vertices[(i + 1) % n];
		signedArea += (p1.X() * p2.Y() - p2.X() * p1.Y());
	}
	signedArea /= 2.0;

	return signedArea < 0; // 返回是否为顺时针（CW）
}

void QFillOperationWidget::FixWireOrientation(TopoDS_Wire& wire, bool isOuter)
{
	// 检查方向（外圈需逆时针，内圈顺时针）
	bool bIsClock = IsWireClockwise(wire);
	if (isOuter && bIsClock)
	{
		wire.Reverse(); // 反转为逆时针
	}
	else if (!isOuter && !bIsClock)
	{
		wire.Reverse(); // 反转为顺时针
	}
}

double QFillOperationWidget::GetWireArea(const TopoDS_Wire& wire)
{
	// 1. 验证 Wire 是否闭合
	if (!BRep_Tool::IsClosed(wire)) {
		throw std::runtime_error("Wire is not closed!");
	}

	// 2. 从 Wire 创建平面面
	BRepBuilderAPI_MakeFace makeFace(wire);
	if (makeFace.Error() != BRepBuilderAPI_FaceDone) {
		throw std::runtime_error("Failed to create face from wire!");
	}
	TopoDS_Face face = makeFace.Face();

	// 3. 计算面的几何属性（面积）
	GProp_GProps gProps;
	BRepGProp::SurfaceProperties(face, gProps);  // 计算面属性
	return gProps.Mass();  // 获取面积
}
